/*
 * DOMXMLConversion.java
 *
 * Created on 6 de octubre de 2007, 04:28 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package wasolicitudesfiec.xml;

import web.util.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.*;
import wasolicitudesfiec.xml.LectorXML;
import web.util.HtmlEntities;

/**
 * 
 * Clase base con la que se proveran metodos para conversion a xml de diferentes objetos,
 * implementando unicamente el una plantilla XML asociada, y los metodos que modifican el XML
 * de esa plantilla y el que a partir del xml genera el objeto
 * @author Luisfer
 */
public abstract class DOMXMLConversion {
    protected final static String STRING_FORMATO_DE_FECHA = "MM/dd/yyyy";
    private final static DateFormat DFormat = new SimpleDateFormat(STRING_FORMATO_DE_FECHA);
    
    protected Document documento=null;
    protected Element rootElement;
    protected String realPath;
    protected String relativePathXML;
    protected static HtmlEntities ENTIDADES=new HtmlEntities();;
    public DOMXMLConversion() {
        this.realPath=wasolicitudesfiec.logicacontrol.Logica.getRealPath();
    }
    public DOMXMLConversion(String realPath){
        this();
        this.realPath=new String(realPath);
    }
    // <editor-fold defaultstate="collapsed" desc=" metodos a probar ">
//    public final void initXMLDOM(String tagnameROOT) throws ParserConfigurationException {
//        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
//        DocumentBuilder builder = builderFactory.newDocumentBuilder();
//        this.documento=builder.newDocument();
//        Element raiz=this.documento.createElement(tagnameROOT);
//        this.documento.appendChild(raiz);
//    }
    // </editor-fold>
    public final void initXMLDOMfromFile(String relativePath){
        this.initXMLDOMfromFile(this.realPath,relativePath);
    }
    public final void initXMLDOMfromFile(String realPath,String relativePath){
        InputSource in;
        LectorXML lectorXML;
        System.out.println("Xml file: "+realPath+relativePath);
        in = new InputSource(realPath+relativePath);
        lectorXML=new LectorXML();
        try {
            this.documento=lectorXML.leerXML(in);
            //remuevo los nodos que no son de tipo ELEMENT_NODE del principio del XML
            while(this.documento.getFirstChild().getNodeType()!=Node.ELEMENT_NODE) {
                this.documento.removeChild(this.documento.getFirstChild());}
        } catch (SAXException ex) {
            System.out.println("EXCEPCION->SAXException EN CONTRUCTOR A XML");
            ex.printStackTrace();
        } catch (ParserConfigurationException ex) {
            System.out.println("EXCEPCION->ParserConfigurationException EN CONTRUCTOR A XML");
            ex.printStackTrace();
        } catch (IOException ex) {
            System.out.println("EXCEPCION->IOException EN CONSTRUCTOR A XML");
            ex.printStackTrace();
        } catch(Exception ex){
            System.out.println("EXCEPCION->Exception sin tipo EN CONSTRUCTOR A XML");
            ex.printStackTrace();
        }
    }
    private void cargarDOMXML(String domxmlSource)throws SAXException, IOException, ParserConfigurationException{
        //estos metodos solo cargan un objeto a DOMXML y solo eso no inicializan los atributos del objeto
        //solo carga un DOMXML a partir de la plantilla
        LectorXML lectorXML=new LectorXML();
        this.documento=lectorXML.leerXML(domxmlSource);
        this.rootElement=this.documento.getDocumentElement();
    }
    private void cargarDOMXML(InputSource domxmlSource)throws SAXException, IOException, ParserConfigurationException{
        LectorXML lectorXML=new LectorXML();
        this.documento=lectorXML.leerXML(domxmlSource);
        this.rootElement=this.documento.getDocumentElement();
    }
    private void cargarDOMXML(InputStream domxmlSource) throws SAXException, IOException, ParserConfigurationException{
        LectorXML lectorXML=new LectorXML();
        this.documento=lectorXML.leerXML(domxmlSource);
        this.rootElement=this.documento.getDocumentElement();
    }
    /**
     * Este metodo asume que se tiene un objeto DOM XML que es una representacion del objeto
     * actual, cargado en memoria, y por lo tanto en dicha asuncion se convierte dicho arbol DOM
     * en la representacion del objeto rellenando todos los atributos que este contiene
     */
    abstract protected void cargarObjetoAPartirDeXML_Interno();
    /**
     * carga una representacion XML de este objeto, y realiza los parsing necesarios
     * para inicializar todos los atributos de este objeto construlendolo completamente
     * a partir de su representacion XML
     * @param xmlSource XML de entrada representada como texto
     */
    public void cargarXML(String xmlSource) throws SAXException, IOException, ParserConfigurationException {
        this.cargarDOMXML(xmlSource);
        this.cargarObjetoAPartirDeXML_Interno();
    }
    /**
     * Carga XML, y lo convierte en su representacion del objeto en cuestion carga una representacion XML de este objeto, y realiza los parsing necesarios
     * para inicializar todos los atributos de este objeto construlendolo completamente
     * a partir de su representacion XML
     * @param xmlSource XML de entrada representada como un InputSource
     */
    public void cargarXML(InputSource xmlSource) throws SAXException, IOException, ParserConfigurationException {
        this.cargarDOMXML(xmlSource);
        this.cargarObjetoAPartirDeXML_Interno();
    }
    /**
     * carga una representacion XML de este objeto, y realiza los parsing necesarios
     * para inicializar todos los atributos de este objeto construlendolo completamente
     * a partir de su representacion XML
     * @param xmlSource XML de entrada representada como un inputStream
     */
    public void cargarXML(InputStream xmlSource) throws SAXException, IOException, ParserConfigurationException {
        this.cargarDOMXML(xmlSource);
        this.cargarObjetoAPartirDeXML_Interno();
    }
    public void cargarXML(Element rootElement){
        this.crearArbolXML();
        Node rootElementOld=this.rootElement;
        Node rootElementNew=this.documento.importNode(rootElement, true);
        this.documento.replaceChild(rootElementNew, rootElementOld);
        // <editor-fold defaultstate="collapsed" desc="borrado">
//////        
//////        NodeList tmpList=rootElement.getChildNodes();
//////        int t=tmpList.getLength();
//////        Node tmp;
////////        this.documento.
////////        rootElement.cl
//////        //buscando otra forma de hacer lo mismo
//////        while(this.rootElement.hasChildNodes()){this.rootElement.removeChild(this.rootElement.getFirstChild());}
//////        for(int i=0; i<t; i+=1 ){
//////            tmp=tmpList.item(i);
//////            //cambiado pues se comete el error de tratar de agregar un objeto DOM en un documento
//////            //this.rootElement.appendChild(tmp);
//////            this.rootElement.appendChild( this.documento.importNode(tmp, true) );
//////        }
        // </editor-fold>
        this.rootElement=this.obtenerElementoRaizDOMXML(); //se obttiene nuevamente la raiz pues el nodo raiz cambio
        this.cargarObjetoAPartirDeXML_Interno();
    }
    /**
     * Crea el XML interno del XML que se este usando:
     * * para el caso de la implementacion usando DOMXML se asume que se obtiene con anterioridad
     *   el rootElement de forma que se usa directamente
     */    
    protected abstract void crearXML_Interno();
    protected void crearArbolXML(String realPath) {
        this.initXMLDOMfromFile(realPath,this.relativePathXML);
        this.rootElement=this.documento.getDocumentElement();
        this.crearXML_Interno();        
    }
    protected void crearArbolXML(){
        this.crearArbolXML(this.realPath);
    }
    protected void setElementText(String elemento,Object valor){
        String txtContenido;
        txtContenido=(valor==null?"":valor.toString());
        this.rootElement.getElementsByTagName(elemento).item(0).setTextContent(txtContenido);
    }
    protected void setElementText(String elemento,Date fecha){
        String txtContenido=fecha==null?"":DFormat.format(fecha);
        this.rootElement.getElementsByTagName(elemento).item(0).setTextContent(txtContenido);
    }
    protected String getElementText(String elemento){
        String txtContenido;
        Node tmpElement=this.rootElement.getElementsByTagName(elemento).item(0);
        txtContenido=tmpElement!=null?tmpElement.getTextContent().trim():null;
        if(txtContenido!=null)txtContenido=(txtContenido.length()!=0?txtContenido:null);
        return txtContenido;
    }
    protected Date getElementTextAsDate(String elemento){
        Date tmp=null;
        String txtContenido=this.getElementText(elemento);
        if(txtContenido==null) return null;
        try{
            tmp=DFormat.parse(txtContenido);
        }catch(ParseException pexc){
            pexc.printStackTrace();
        }
        return tmp;
    }
    protected Integer getElementTextAsInteger(String elemento){
        String txtContenido=this.getElementText(elemento);
        if(txtContenido==null) return null;
        return new Integer(txtContenido);
    }
    protected Double getElementTextAsDouble(String elemento){
        String txtContenido=this.getElementText(elemento);
        if(txtContenido==null) return null;
        return new Double(txtContenido);
    }
    protected Boolean getElementTextAsBoolean(String elemento){
        String txtContenido=this.getElementText(elemento);
        if(txtContenido==null) return null;
        return new Boolean(txtContenido);
    }

    private String convertDOMXMLtoString(){
        String xml=null;
        try{
            TransformerFactory tranFactory = TransformerFactory.newInstance();
            Transformer aTransformer = tranFactory.newTransformer();
            Source srcDocument = new DOMSource( this.documento );
            
            StringWriter writer=new StringWriter();
            Result resultado=new StreamResult(writer);
            
            aTransformer.transform(srcDocument,resultado);
            xml=writer.toString();
            writer.flush();
        }catch(TransformerConfigurationException e) {
            System.out.println("EXCEPCION->TransformerConfigurationException EN conversion A XML-String");
            e.printStackTrace();
        } catch(TransformerException e){
            System.out.println("EXCEPCION->TransformerException EN conversion A XML-String");
            e.printStackTrace();
        }finally{}
        return xml;
    }
    
    public Element obtenerElementoRaizDOMXML(){
        if(this.documento==null){
            this.crearArbolXML();            
        }
//        return this.documento.getDocumentElement();
        return this.documento.getDocumentElement();
    }
    /**
     * Convierte el objeto actual en una representacion XML del mismo objeto basado en la plantilla XML
     * @return XML como un String del objeto actual
     * @param realPath la ruta real donde se encuentra el proyecto web, pues a partir de esta ruta y la ruta relativa que se
     * usa de forma interna se puede llegar a el archivo XML de plantilla
     */
    public String toXMLString(String realPath){
        this.crearArbolXML(realPath);
        return this.convertDOMXMLtoString();
    }

    public String toXMLString(){
        this.crearArbolXML();
        return this.convertDOMXMLtoString();
    }
}
